
type Constructor = new (...args: unknown[]) => any;

function logClass(target: Constructor, ctx: ClassDecoratorContext) {
  console.log(`class ${target.name} has been decorated`);
  console.log(target);
  console.log(`kind: ${ctx.kind}, name: [${ctx.name}]`);
}

function handleException(target: Function, ctx: ClassMethodDecoratorContext) {
  console.log(target);
  console.log(`name: [${String(ctx.name)}]`);
  
  ctx.addInitializer(function() {
    (this as any)[ctx.name] = (this as any)[ctx.name].bind(this);
  });

  return function(this: unknown, ...args: unknown[]) {
    console.log('entering function...')
    const fn = ctx.access.get(this);
    console.log(fn);
    console.log('function called...');
    const ret = target.apply(this, args);
    console.log(`leaving function...`);
    return ret;
  }
}

/**
 * 异常处理程序
 */
class Example {

  @handleException
  out() {
    console.log(this);
    console.log('out method called.');
  }
}


function main() {
  console.log('main first line.');
  const e0 = new Example();
  e0.out();
}

main();

// npx esbuild a.ts --bundle --outfile=a.js && node a.js
